/**
 * @brief 
 * @author zhangpeihao
 */
#include <zsystem/core/networking/connection.h>
#include <zsystem/core/common/logdump.h>
#include <event2/event.h>

void
zsystem::listenerContainer::doCallback(tcpConnection* connection, const Z_U16 seqId, const Z_U16 msgId, char* const buffer, const Z_U16 len)
{
  msgReceivedListener listener(_defaultListener);
  if ( !connection->isAuth() && msgId >= DEFAULT_MAX_AUTH_MSG_ID )
  {
    LOG(WARNING) << "Received message before auth !!! from: " << connection->getRemoteAddressString();
    connection->close();
    return;
  }
  if ( msgId <= _maxMsgId && _listenerMap[msgId] != Z_NULL )
  {
    listener = _listenerMap[msgId];
  }

  try{
    listener(this, connection, seqId, msgId, buffer, len);
  }
  catch(...){
    LOG(WARNING) << "callback(msgId = " << msgId << ") exception catched" ;
  }
}

const Z_BOOL 
zsystem::tcpConnection::send(const Z_U16 msgId, const char* buffer, const Z_U16 len)
{
  // Todo: check send buffer block!
  zsystem::packet* packet = Z_NEW(zsystem::packet) (_seqId.inc(), msgId, len, buffer);
  _sendQueue->push(packet);
  bufferevent_enable(_evbuf, EV_WRITE);
  return Z_TRUE;
}

const Z_BOOL 
zsystem::tcpConnection::response(const Z_U16 seqId, const Z_U16 msgId, const char* const buffer, const Z_U16 len)
{
  // Todo: check send buffer block!
  zsystem::packet* packet = Z_NEW(zsystem::packet) (seqId, msgId, len, buffer);
  _sendQueue->push(packet);
  bufferevent_enable(_evbuf, EV_WRITE);
  return Z_TRUE;
}

void 
zsystem::tcpConnection::close()
{
  if ( _evbuf != Z_NULL )
  {
    bufferevent_disable(_evbuf, EV_WRITE | EV_READ);
    bufferevent_free(_evbuf);
    _evbuf = Z_NULL;
  }
  if (_socket != Z_NULL)
  {
    _socket->close();
    Z_SAFE_DELETE(_socket, ~tcpSocket);
  }
}

void 
zsystem::tcpConnection::cleanup()
{
  // clean up send queue
  zsystem::packet** packet = _sendQueue->pop();
  while ( packet != Z_NULL)
  {
    Z_SAFE_DELETE((*packet), ~packet);
    packet = _sendQueue->pop();
  }
}

zsystem::tcpConnection::~tcpConnection()
{
  LOG(INFO)<<"zsystem::tcpConnection::~tcpConnection(): this: " << (Z_PTR_TYPE)this;
  this->close();
  Z_SAFE_DELETE(_sendQueue, ~stdQueue);
  Z_SAFE_DELETE(_receivePacket, ~packet);
}

zsystem::tcpConnection::tcpConnection(zsystem::listenerContainer* listener, const Z_I32 sendBufferSize, const Z_I32 recieveBufferSize, const Z_I32 keepAliveInterval)
: _socket(Z_NULL)
, _receivePacket(Z_NULL)
, _listener(listener)
, _sendQueue(Z_NULL)
, _evbuf(Z_NULL)
, _seqId(1)
, _received(0)
, _mark(0)
, _removedAt(0)
, _id(0)
, _connected(Z_FALSE)
, _authPass(Z_FALSE)
{
  LOG(INFO)<<"zsystem::tcpConnection::tcpConnection(): this: " << (Z_PTR_TYPE)this;
  _socket = Z_NEW(zsystem::tcpSocket) (sendBufferSize, recieveBufferSize, Z_FALSE, keepAliveInterval);
  Z_ASSERT_ALL(_socket != Z_NULL);
  Z_ASSERT_ALL(_listener != Z_NULL);

  _sendQueue = Z_NEW(sendQueueType) (0);
  Z_ASSERT_ALL(_sendQueue != Z_NULL);
}

zsystem::tcpConnection::tcpConnection(zsystem::listenerContainer* listener, const Z_SOCKET_HANDLE& socket, const Z_SOCKET_ADDRESS& address, const Z_I32 sendBufferSize, const Z_I32 recieveBufferSize, const Z_I32 keepAliveInterval)
: _socket(Z_NULL)
, _receivePacket(Z_NULL)
, _listener(listener)
, _sendQueue(Z_NULL)
, _evbuf(Z_NULL)
, _seqId(1)
, _received(0)
, _mark(0)
, _removedAt(0)
, _id(0)
, _connected(Z_FALSE)
, _authPass(Z_FALSE)
{
  LOG(INFO)<<"zsystem::tcpConnection::tcpConnection(): this: " << (Z_PTR_TYPE)this;
  _socket = Z_NEW(zsystem::tcpSocket) (socket, address, sendBufferSize, recieveBufferSize, Z_TRUE, keepAliveInterval);
  Z_ASSERT_ALL(_socket != Z_NULL);
  Z_ASSERT_ALL(_listener != Z_NULL);
  _sendQueue = Z_NEW(sendQueueType) (0);
  Z_ASSERT_ALL(_sendQueue != Z_NULL);
}

zsystem::tcpConnection::tcpConnection(const Z_U32 id, zsystem::listenerContainer* listener, zsystem::tcpSocket* socket)
: _socket(socket)
, _receivePacket(Z_NULL)
, _listener(listener)
, _sendQueue(Z_NULL)
, _evbuf(Z_NULL)
, _seqId(1)
, _received(0)
, _mark(0)
, _removedAt(0)
, _id(id)
, _connected(Z_FALSE)
, _authPass(Z_FALSE)
{
  LOG(INFO)<<"zsystem::tcpConnection::tcpConnection(): this: " << (Z_PTR_TYPE)this;
  Z_ASSERT_ALL(_listener != Z_NULL);
  _sendQueue = Z_NEW(sendQueueType) (0);
  Z_ASSERT_ALL(_sendQueue != Z_NULL);
}

#if 0
const Z_I32 receive(zsystem::tcpSocket& socket, char* const buffer, const Z_U16 len)
{
  Z_I32 received(0);

  received = socket.receive(buffer, len);
  if ( received < 0 )
  {
    if ( socket.isEAgain() )
    {
      LOG(INFO) << "receive blocked";
      return 0;
    }
    LOG(WARNING) << "receive error 1";
    return -1;
  }
  else if ( received == 0 )
  {
    LOG(WARNING) << "receive error 2";
    return -1;
  }
  return received;
}
#endif

void 
zsystem::tcpConnection::readCallback(Z_EV_BUFFER_EVENT* ev, void* arg)
{
  LOG(INFO) << "zsystem::tcpConnection::readCallback() begin";
  zsystem::tcpConnection* conn = (zsystem::tcpConnection*)arg;
  Z_EV_BUF* input = bufferevent_get_input(ev);

  LOG(INFO) << "zsystem::tcpConnection::readCallback() length = " << evbuffer_get_length(input);

  while ( evbuffer_get_length(input) > 0 )
  {
    if ( !conn->read(input) )
    {
      conn->close();
      break;
    }
  }
  LOG(INFO) << "zsystem::tcpConnection::readCallback() end";
}

void 
zsystem::tcpConnection::writeCallback(Z_EV_BUFFER_EVENT* ev, void* arg)
{
  LOG(INFO) << "zsystem::tcpConnection::writeCallback() begin";
  zsystem::tcpConnection* conn = (zsystem::tcpConnection*)arg;
  if ( !conn->_connected )
  {
    conn->connectionCallback(ev, BEV_EVENT_CONNECTED, arg);
  }
  else
  {
    Z_EV_BUF* output = bufferevent_get_output(ev);

    if ( !conn->write(output) )
    {
      LOG(INFO) << "connection write failed";
      conn->close();
    }
    else
    {
      bufferevent_enable(conn->_evbuf, EV_READ);
    }
  }
  LOG(INFO) << "zsystem::tcpConnection::writeCallback() end";
}

void 
zsystem::tcpConnection::connectionCallback(Z_EV_BUFFER_EVENT* ev, short what, void* arg)
{
  LOG(INFO) << "zsystem::tcpConnection::connectionCallback(what: " << what <<") begin";
  zsystem::tcpConnection* conn = (zsystem::tcpConnection*)arg;
  Z_BOOL connected(Z_FALSE);
	if (what & BEV_EVENT_CONNECTED)
  {
  	int error;
    Z_SOCKLEN errsz = sizeof(error);
	  if ( getsockopt(conn->_socket->getSocketHandle(), SOL_SOCKET, SO_ERROR, (char *)&error, &errsz) != -1 ) 
    {
      if ( !error )
      {
        connected = Z_TRUE;
      }
      else
      {
        LOG(WARNING) << "check connection error";
      }
	  }
	}

  if ( connected && !conn->_connected )
  {
    conn->_connected = Z_TRUE;
    bufferevent_enable(conn->_evbuf, EV_WRITE | EV_READ);
    conn->onConnected(conn);
  }
  else
  {
    if (conn->_connected)
    {
      conn->_connected = Z_FALSE;
      conn->onDisconnected(conn);
    }
    if ( what & BEV_EVENT_EOF)
    {
      LOG(INFO) << "connection closed";
    }
    else
    {
      LOG(WARNING) << "connection error, what: " << what;
    }
    conn->close();
    conn->_removedAt = (Z_I32)time(Z_NULL); 
  }
  LOG(INFO) << "zsystem::tcpConnection::connectionCallback() end";
}

const Z_BOOL
zsystem::tcpConnection::read(Z_EV_BUF* input)
{
  Z_I32 received(0);
  if ( _receivePacket == Z_NULL)
  {
    _receivePacket = Z_NEW(zsystem::packet)();
    _received = 0;
  }

  // Read head
  if ( _received < Z_PACKET_HEAD_SIZE)
  {
    received = evbuffer_remove(input, _receivePacket->getHeadData() + _received, Z_PACKET_HEAD_SIZE - _received);
    if ( received == Z_PACKET_HEAD_SIZE - _received )
    {
      _received = Z_PACKET_HEAD_SIZE;
      if ( !_receivePacket->allocByHead() )
      {
        LOG(WARNING) << "Allocate receive buffer failed";
        return Z_FALSE;
      }
    }
    else if ( received == -1 )
    {
      LOG(WARNING) << "read head failed!";
      return Z_FALSE;
    }
    else
    {
      _received += received;
      return Z_TRUE;
    }
  }

  // Read body
  Z_I32 offset = _received - Z_PACKET_HEAD_SIZE;
  Z_I32 remain = _receivePacket->getDataSize() - offset;
  received = evbuffer_remove(input, _receivePacket->getData() + offset, remain);
  if ( received == remain )
  {
    // Packet received finish
    LOG(INFO) << "Recevied packet, size: " << _receivePacket->getDataSize();
    _listener->doCallback(this, _receivePacket->getSeqId(), _receivePacket->getMsgId(), _receivePacket->getData(), _receivePacket->getDataSize());
    Z_SAFE_DELETE(_receivePacket, ~packet);
    _receivePacket = Z_NULL;
  }
  else if ( received >= 0 )
  {
    LOG(INFO) << "remain: " << (remain - received);
    _received += received;
  }
  else
  {
    LOG(WARNING) << "read body failed!";
    return Z_FALSE;
  }
  return Z_TRUE;
}

const Z_BOOL
zsystem::tcpConnection::write(Z_EV_BUF* output)
{
  zsystem::packet** packet = _sendQueue->pop();
  if ( packet != Z_NULL )
  {
    zsystem::packet* pack = *packet;
    if ( evbuffer_add(output, pack->getHeadData(), Z_PACKET_HEAD_SIZE) != 0 )
    {
      LOG(WARNING) << "Write head failed";
      return Z_FALSE;
    }

    if ( evbuffer_add(output, pack->getData(), pack->getDataSize()) != 0 )
    {
      LOG(WARNING) << "Write body failed";
      return Z_FALSE;
    }

    // Todo: check send buffer

    Z_SAFE_DELETE(pack, ~packet);
  }

  return Z_TRUE;
}

#pragma warning(disable: 4355)
/////////////////////////////////////////////////////////////////////////////////////////////////////
zsystem::tcpClient::tcpClient(zsystem::msgReceivedListener defaultListener, const Z_I32 sendBufferSize, 
                              const Z_I32 recieveBufferSize, Z_EV_BASE* base)
: zsystem::tcpConnection(this, sendBufferSize, recieveBufferSize, 0)
, zsystem::listenerContainer(defaultListener)
, _evbase(base)
, _thread(Z_NULL)
, _newBase((base == Z_NULL))
{
  _authPass = Z_TRUE; // No auth in client part
}
#pragma warning(default: 4355)

zsystem::tcpClient::~tcpClient()
{
}

Z_BOOL 
zsystem::tcpClient::connect(const char* serverAddress)
{
  if ( _socket->connect(serverAddress) )
  {
    if ( _newBase )
    {
      _evbase = event_base_new();
      Z_ASSERT_ALL(_evbase != Z_NULL);
    }

    _evbuf = bufferevent_socket_new(_evbase, _socket->getSocketHandle(), BEV_OPT_CLOSE_ON_FREE|BEV_OPT_THREADSAFE);
    Z_ASSERT_ALL(_evbuf != Z_NULL);

    bufferevent_setcb(_evbuf, readCallback, writeCallback, connectionCallback, this);
    bufferevent_enable(_evbuf, EV_WRITE);

    if ( _newBase )
    {
      _thread = Z_NEW(zsystem::thread) (threadMain, this);
      return _thread->start();
    }
    return Z_TRUE;
  }
  return Z_FALSE;
}

void 
zsystem::tcpClient::close()
{
  zsystem::tcpConnection::close();
  if ( _evbase != Z_NULL )
  {
    event_base_loopbreak(_evbase);
    if ( _newBase )
    {
      event_base_free(_evbase);
    }
    _evbase = Z_NULL;
  }
  if ( _evbuf != Z_NULL )
  {
    bufferevent_free(_evbuf);
    _evbuf = Z_NULL;
  }
  if ( _thread != Z_NULL )
  {
    _thread->join();
    Z_SAFE_DELETE(_thread, ~thread);
    _thread = Z_NULL;
  }
  cleanup();
}

void 
zsystem::tcpClient::threadMain(Z_PTR arg)
{
  Z_DUMP_LOG("zsystem::tcpClient::threadMain() begin");
  zsystem::tcpClient* conn = (zsystem::tcpClient*)arg;
  event_base_dispatch(conn->_evbase);

  Z_DUMP_LOG("zsystem::tcpClient::threadMain() exit");
}


/////////////////////////////////////////////////////////////////////////////////////////////////////
zsystem::tcpServerConnection::tcpServerConnection(const Z_U32 id, zsystem::tcpServer* server, zsystem::tcpServerThread* thread, zsystem::tcpSocket* socket)
: zsystem::tcpConnection(id, server, socket)
, _server(server)
, _thread(thread)
{
  _id = id;
  _evbuf = bufferevent_socket_new(_thread->getBase(), _socket->getSocketHandle(), BEV_OPT_CLOSE_ON_FREE|BEV_OPT_THREADSAFE);
  Z_ASSERT_ALL(_evbuf != Z_NULL);

  bufferevent_setcb(_evbuf, readCallback, writeCallback, connectionCallback, this);
  bufferevent_enable(_evbuf, EV_WRITE);
}

zsystem::tcpServerConnection::~tcpServerConnection()
{
  cleanup();
}

void 
zsystem::tcpServerConnection::close()
{
  if ( _server->close(_id) ) 
  {
    tcpConnection::close();
  }
}

void 
zsystem::tcpServerConnection::doClose()
{
  tcpConnection::close();
}
/////////////////////////////////////////////////////////////////////////////////////////

zsystem::tcpServer::tcpServer(zsystem::msgReceivedListener defaultListener, const char* bindAddress, const Z_I32 sendBufferSize,
                              const Z_I32 recieveBufferSize, const Z_I32 keepAliveInterval, const Z_U16 threads, const Z_I32 backlog)
: zsystem::listenerContainer(defaultListener)
, _threadPool(Z_NULL)
, _bindAddress(Z_NULL)
, _listenSocket(Z_NULL)
, _acceptThread(Z_NULL)
, _connectionMap(Z_NULL)
, _evbase(Z_NULL)
, _timestampEvent(Z_NULL)
, _sendBufferSize(sendBufferSize)
, _recieveBufferSize(recieveBufferSize)
, _keepAliveInterval(keepAliveInterval)
, _backlog(backlog)
, _motoTimestamp((Z_I32)time(Z_NULL))
, _connectionIdAlloc(0)
, _threads(threads)
, _exit(0)
{
  Z_I32 addressLen = strnlen(bindAddress, 1024);
  _bindAddress =(char*) Z_MALLOC(addressLen+1);
#ifdef __WIN32__
  strncpy_s(_bindAddress, addressLen + 1, bindAddress, addressLen);
#else
  strncpy(_bindAddress, bindAddress, addressLen);
#endif
  _bindAddress[addressLen] = '\0';

  _connectionMap = Z_NEW(zsystem::tcpServerConnectionMap) (65535);
  _tv.tv_sec = MONO_TIMESTAMP_SECOND;
	_tv.tv_usec = MONO_TIMESTAMP_USECOND; // 0.2 second

  _releaseConnectionList = Z_NEW(tcpServerConnectionQueue) (65535);

}

zsystem::tcpServer::~tcpServer()
{
  stop();
  Z_SAFE_DELETE(_connectionMap, ~stdMap);

  if ( _bindAddress != Z_NULL )
  {
    Z_FREE(_bindAddress);
    _bindAddress = Z_NULL;
  }
  if ( Z_NULL != _timestampEvent )
  {
    Z_FREE(_timestampEvent);
    _timestampEvent = Z_NULL;
  }
  tcpServerConnection** connection = _releaseConnectionList->pop();
  while ( connection != Z_NULL )
  {
      (*connection)->~tcpServerConnection();
      Z_FREE(*connection);
      connection = _releaseConnectionList->pop();
  }
  Z_SAFE_DELETE(_releaseConnectionList, ~stdQueue);

}

const Z_BOOL 
zsystem::tcpServer::start()
{
  if ( _threadPool == Z_NULL )
  {

    _threadPool = Z_NEW(zsystem::evThreadPoolM) (_threads, threadInit, this);
    Z_ASSERT_RETURN( _threadPool != Z_NULL, Z_FALSE );
    Z_ASSERT_RETURN( _threadPool->start(), Z_FALSE )

    _listenSocket = Z_NEW(zsystem::tcpSocket) (_sendBufferSize, _recieveBufferSize, Z_TRUE, _keepAliveInterval);
    Z_ASSERT_RETURN( _listenSocket != Z_NULL, Z_FALSE );
    Z_ASSERT_RETURN( _listenSocket->bind(_bindAddress), Z_FALSE )
    Z_ASSERT_RETURN( _listenSocket->listen(_backlog), Z_FALSE );

    _exit.set(0);
    _acceptThread = Z_NEW(zsystem::thread) ( threadAccpetMian, this );
    Z_ASSERT_RETURN( _acceptThread != Z_NULL, Z_FALSE );
    Z_ASSERT_RETURN( _acceptThread->start(), Z_FALSE );
    return Z_TRUE;
  }
  return Z_FALSE;
}

void 
zsystem::tcpServer::stop()
{
  if ( _evbase != Z_NULL )
  {
    event_base_loopbreak(_evbase);
  }

  if ( _threadPool != Z_NULL )
  {
    LOG(INFO)<<"zsystem::tcpServer::stop() _threadPool->stop()";
    google::FlushLogFiles(INFO);
    _threadPool->stop();
    Z_SAFE_DELETE(_threadPool, ~evThreadPool);
  }

  if ( _listenSocket  != Z_NULL )
  {
    LOG(INFO)<<"zsystem::tcpServer::stop() _listenSocket->close()";
    google::FlushLogFiles(INFO);
    _listenSocket->close();
    Z_SAFE_DELETE(_listenSocket, ~tcpSocket);
  }
  if ( _acceptThread  != Z_NULL )
  {
    LOG(INFO)<<"zsystem::tcpServer::stop() _acceptThread->join()";
    google::FlushLogFiles(INFO);
    _exit.set(1);
    _acceptThread->join();
    Z_SAFE_DELETE(_acceptThread, ~thread);
  }

  LOG(INFO)<<"zsystem::tcpServer::stop() Remove all connections";
  google::FlushLogFiles(INFO);
  // Remove all connections
  Z_I32 key;
  Z_PTR data;
  while( _connectionMap->getNumber() > 0 )
  {
    tcpServerConnectionMap::iterator it = _connectionMap->begin();
    if ( _connectionMap->get(it, key, data) )
    {
      close(key);
    }
  }
    LOG(INFO)<<"zsystem::tcpServer::stop() end";
    google::FlushLogFiles(INFO);
}

const Z_BOOL 
zsystem::tcpServer::close(const Z_I32 connectionId)
{
  Z_PTR ret(Z_NULL);
  if( _connectionMap->remove(connectionId, ret) )
  {
    Z_DUMP_LOG( "Remove connection from server" );
  }
  else
  {
    return Z_FALSE;
  }

  if ( ret == Z_NULL )
  {
    return Z_FALSE;
  }

  tcpServerConnection* connection = (tcpServerConnection*)ret;
  connection->doClose();
  _releaseConnectionList->push(connection);

  return Z_TRUE;
}

void 
zsystem::tcpServer::threadInit(Z_PTR thread, Z_PTR initarg)
{
}

void 
zsystem::tcpServer::threadAccpetMian(Z_PTR arg)
{
  Z_DUMP_LOG( "threadAccpetMian() begin" );
  zsystem::tcpServer& server = *((zsystem::tcpServer*)arg);
  zsystem::tcpSocket& serverSocket = *server._listenSocket;

  // libevent
  server._evbase = event_base_new();
  Z_ASSERT_ALL(server._evbase != Z_NULL);

  Z_EV_SRV* srv = evconnlistener_new(server._evbase, onAccept, arg, LEV_OPT_REUSEABLE|LEV_OPT_CLOSE_ON_EXEC|LEV_OPT_CLOSE_ON_FREE, 0, serverSocket.getSocketHandle());
  Z_ASSERT_ALL(srv != Z_NULL);
//  evconnlistener_set_cb(srv, onAccept, arg);

  // monotony timestamp event
  server._timestampEvent = (Z_EV*)Z_MALLOC(sizeof(Z_EV));
  evtimer_assign( server._timestampEvent, server._evbase, onUpdateTimestamp, arg);

  evtimer_add(server._timestampEvent, &server._tv);

  event_base_dispatch(server._evbase);
  evconnlistener_free(srv);
  event_base_free(server._evbase);
  server._evbase = Z_NULL;
  Z_FREE(server._timestampEvent);
  server._timestampEvent = Z_NULL;


  //Z_SOCKET_HANDLE socket;
  //Z_SOCKET_ADDRESS address;
  //while ( !server._exit.get() )
  //{
  //  if ( serverSocket.accept(socket, address) )
  //  {
  //    zsystem::tcpSocket* newSocket = Z_NEW(zsystem::tcpSocket) (socket, address, server._sendBufferSize, server._recieveBufferSize, Z_TRUE, server._keepAliveInterval);
  //    server._threadPool->defer(onNewConnection, newSocket);
  //  }
  //};
  Z_DUMP_LOG( "threadAccpetMian end");
}

void 
zsystem::tcpServer::onUpdateTimestamp(Z_SOCKET_HANDLE fd, Z_I16 ev, Z_PTR arg)
{
  zsystem::tcpServer& server = *((zsystem::tcpServer*)arg);
  Z_I32 now = (Z_I32)time(Z_NULL);
  if ( now > server._motoTimestamp )
  {
    server._motoTimestamp = now;
    // Todo: release connections.
    tcpServerConnection** connection = server._releaseConnectionList->front();
    while ( connection != Z_NULL && (*connection)->_removedAt + 5 < now )
    {
      server._releaseConnectionList->pop();
      (*connection)->~tcpServerConnection();
      Z_FREE(*connection);
      connection = server._releaseConnectionList->front();
    }
  }

  evtimer_add(server._timestampEvent, &(server._tv));
}

void 
zsystem::tcpServer::onNewConnection(Z_PTR thr, Z_PTR arg, Z_PTR initarg)
{
  Z_DUMP_LOG("zsystem::tcpServer::onNewConnection() begin");
  zsystem::tcpServerThread* thread = (zsystem::tcpServerThread*)thr;
  zsystem::tcpSocket* socket = (zsystem::tcpSocket*)arg;
  zsystem::tcpServer* server = (zsystem::tcpServer*)initarg;

  Z_U32 connectionId = server->_connectionIdAlloc.inc();
  Z_PTR data;
  while ( server->_connectionMap->lookup(connectionId, data) )
  {
    connectionId = server->_connectionIdAlloc.inc();
  }
  zsystem::tcpServerConnection* newConnection = Z_NEW(zsystem::tcpServerConnection) (connectionId, server, thread, socket);
  server->_connectionMap->insert(connectionId, newConnection);

  Z_DUMP_LOG("zsystem::tcpClient::onNewConnection() exit");

}

void 
zsystem::tcpServer::onAccept(zsystem::Z_EV_SRV* srv, evutil_socket_t nfd, struct sockaddr *peer_sa, int peer_socklen, Z_PTR arg)
{
  zsystem::tcpServer& server = *((zsystem::tcpServer*)arg);
  Z_SOCKET_ADDRESS addr;
  memcpy(&addr, peer_sa, sizeof(addr));

  zsystem::tcpSocket* newSocket = Z_NEW(zsystem::tcpSocket) (nfd, addr, server._sendBufferSize, server._recieveBufferSize, Z_TRUE, server._keepAliveInterval);
  server._threadPool->defer(onNewConnection, newSocket);
}

